/****************************************************************
 *  This file created by writerB.php on 03/18/2007 at 09:52:32  *
 ****************************************************************
 *  writerB.php created by Tonk (tonk@ctonk.com) in 2007        *
 ****************************************************************
 *                 General Document Information
 *
 *  File Name: room.cpp
 *  Class Name: Room
 *  Data members: 11
 *  Notes:
 ****************************************************************/

#include <iostream>
#include <fstream>
#include "stringutil.h"
#include "definitions.h"
#include "combined.h"
#include "exit.h"
#include "log.h"
#include "world.h"



int Room::numRooms = 0;
int Room::roomIndex = 0;


// Additional constructors...
Room::Room( const unsigned& vnum, Area* area ) { // This constructor acts as a default constructor as well.
	setRoomID( ++roomIndex );
	setVnum( vnum );
	setSector( 0 );
	setFlags( 0 );
	setArea( area );
	setDescolor( '\0' );
	// Increment the object count...
	numRooms++;
}

// Copy constructor (Doesn't change _RoomID)...
Room::Room( Room& ref ) {
	setRoomID( ++roomIndex );
	setVnum( ref.getVnum() );
	setSector( ref.getSector() );
	setFlags( ref.getFlags() );
	setArea( ref.getArea() );
	setName( ref.getName() );
	setDesc( ref.getDesc() );
	setDescolor( ref.getDescolor() );
	for ( int i=0; i < 6; i++ )
		setExit( i, ref.getExit( i ) );
	// Increment the object count...
	numRooms++;
}

// Destructor...
Room::~Room() {
	// We have to iterate through every room to disable any
	// exits which point to this soon-to-be-destroyed room.
	for ( std::map<std::string,Area*>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it )
		for ( std::vector< Room* >::iterator r_it = (*a_it).second->getRooms().begin(); r_it != (*a_it).second->getRooms().end(); ++r_it )
			for ( unsigned u=0; u < 6; u++ )
				if ( (*r_it)->getExit( u )->getPoint() == getVnum() ) {
					(*r_it)->getExit( u )->setThere( false );
					(*r_it)->getExit( u )->setPoint( 0 );
				}
	// We have to destroy all Objects, Mobs, and Resets in this Room...
	for ( std::vector< Object* >::iterator it = getObjects().begin(); getObjects().size(); it = getObjects().begin() ) {
		World::Instance().drop( *it );
		drop( *it );
		delete (*it);
	}
	for ( std::vector< Mob* >::iterator it = getMobs().begin(); getMobs().size(); it = getMobs().begin() ) {
		World::Instance().drop( *it );
		drop( *it );
		delete (*it);
	}
	for ( std::map<std::string,Area*>::iterator a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it )
		for ( std::vector< Reset* >::iterator r_it = (*a_it).second->getResets().begin(); r_it != (*a_it).second->getResets().end(); )
			if ( (*r_it)->getVnum() == getVnum() ) {
				r_it = (*a_it).second->getResets().erase( r_it );
				delete (*r_it);
			} else
				++r_it;
	// Decrement the object count...
	numRooms--;
}

// Assignment operator (Doesn't change _RoomID)...
Room& Room::operator = ( Room& ref ) {
	setVnum( ref.getVnum() );
	setSector( ref.getSector() );
	setFlags( ref.getFlags() );
	setArea( ref.getArea() );
	setName( ref.getName() );
	setDesc( ref.getDesc() );
	setDescolor( ref.getDescolor() );
	for ( int i=0; i < 6; i++ )
		setExit( i, ref.getExit( i ) );
	return *this;
}

// Equality operator (Compares _vnum)...
bool Room::operator == ( Room& ref ) {
	return ( getVnum() == ref.getVnum() );
}

// Inequality operator (Compares _vnum)...
bool Room::operator != ( Room& ref ) {
	return ( getVnum() != ref.getVnum() );
}

// Less than operator (Compares _vnum)...
bool Room::operator < ( const Room& ref ) const {
	return ( getVnum() < ref.getVnum() );
}

// Greater than operator (Compares _vnum)...
bool Room::operator > ( const Room& ref ) const {
	return ( getVnum() > ref.getVnum() );
}

// Subscript operator returns the exit at offset i...
Exit& Room::operator [] ( const unsigned& i ) {
	return *(getExit( i ));
}

// Protected Methods...
void Room::setRoomID( const int& RoomID ) { // protected
	_RoomID = RoomID;
}

void Room::setDescolor( const char& descolor ) { // protected
	_descolor = descolor;
	return;
}

// Public accessor methods...
int Room::getRoomID( void ) const { // public
	return _RoomID;
}

void Room::setVnum( const unsigned& vnum ) { // public
	_vnum = vnum;
	return;
}

unsigned Room::getVnum( void ) const { // public
	return _vnum;
}

void Room::setSector( const unsigned& sector ) { // public
	_sector = sector;
	switch ( getSector() ) {
		case INDOOR:		setDescolor( 'x' ); break;
		case CITY:			setDescolor( 'x' ); break;
		case FOREST:		setDescolor( 'g' ); break;
		case PLAINS:		setDescolor( 'G' ); break;
		case SWAMP:			setDescolor( 'w' ); break;
		case MOUNTAIN:		setDescolor( 'y' ); break;
		case ROAD: 			setDescolor( 'x' ); break;
		case UNDERWATER:	setDescolor( 'B' ); break;
		case GRAVEYARD:		setDescolor( 'w' ); break;
		case CHURCH:		setDescolor( 'W' ); break;
		case ARENA:			setDescolor( 'x' ); break;
		default:			setDescolor( 'x' ); break;
	}
	return;
}

unsigned Room::getSector( void ) const { // public
	return _sector;
}

void Room::setFlags( const unsigned& flags ) { // public
	_flags = flags;
	return;
}

unsigned Room::getFlags( void ) const { // public
	return _flags;
}

void Room::setArea( Area* area ) { // public
	_area = area;
	return;
}

Area* Room::getArea( void ) const { // public
	return _area;
}

void Room::setName( const std::string& name ) { // public
	_name = name;
	return;
}

std::string Room::getName( void ) const { // public
	return _name;
}

void Room::setDesc( const std::string& desc ) { // public
	_desc = desc;
	return;
}

std::string Room::getDesc( void ) const { // public
	return _desc;
}

std::string* Room::getDescP( void ) { // public
	return &_desc;
}

char Room::getDescolor( void ) const { // public
	return _descolor;
}

Exit* Room::getExit( const unsigned& i ) { // public
	if ( i < 6 )
		return &(_exits[i]);
	else
		return NULL;
}

void Room::setExit( const unsigned& i, Exit* exit ) { // public
	if ( i < 6 )
		_exits[i] = *exit;
	return;
}

std::vector< Character* >& Room::getCharacters( void ) { // public
	return _characters;
}

Character* Room::add( Character* character ) { // public
	if ( character )
		getCharacters().push_back( character );
	return character;
}

Character* Room::getCharacter( const int& i ) { // public
	if ( i < 0 || (unsigned)i < getCharacters().size() )
		return NULL;
	else
		return getCharacters().at( i );
}

Character* Room::getCharacter( const std::string& name ) { // public
	for ( std::vector< Character* >::iterator it = getCharacters().begin(); it != getCharacters().end(); ++it )
		if ( str_prefix( name, (*it)->getName() ) )
			return *it;
	return NULL;
}

bool Room::drop( Character* character ) { // public
	for ( std::vector< Character* >::iterator it = getCharacters().begin(); it != getCharacters().end(); it++ )
		if ( (*it) == character ) {
			getCharacters().erase( it );
			return true;
		}
	return false;
}

bool Room::dropCharacter( std::string& name ) { // public
	for ( std::vector< Character* >::iterator it = getCharacters().begin(); it != getCharacters().end(); it++ )
		if ( (*it)->getName() == name ) {
			getCharacters().erase( it );
			return true;
		}
	return false;
}

std::vector< Mob* >& Room::getMobs( void ) { // public
	return _mobs;
}

Mob* Room::add( Mob* mob ) { // public
	if ( mob )
		getMobs().push_back( mob );
	return mob;
}

Mob* Room::getMob( const int& i ) { // public
	if ( i < 0 || (unsigned)i < getMobs().size() )
		return NULL;
	else
		return getMobs().at( i );
}

Mob* Room::getMob( const std::string& name ) { // public
	for ( std::vector< Mob* >::iterator it = getMobs().begin(); it != getMobs().end(); ++it )
		if ( strstr( (*it)->getName(), name ) )
			return *it;
	return NULL;
}

bool Room::drop( Mob* mob ) { // public
	for ( std::vector< Mob* >::iterator it = getMobs().begin(); it != getMobs().end(); it++ )
		if ( (*it) == mob ) {
			getMobs().erase( it );
			return true;
		}
	return false;
}

bool Room::dropMob( std::string& name ) { // public
	for ( std::vector< Mob* >::iterator it = getMobs().begin(); it != getMobs().end(); it++ )
		if ( (*it)->getName() == name ) {
			getMobs().erase( it );
			return true;
		}
	return false;
}

std::vector< Object* >& Room::getObjects( void ) { // public
	return _objects;
}

Object* Room::add( Object* object ) { // public
	if ( object )
		getObjects().push_back( object );
	return object;
}

Object* Room::getObject( const int& i ) { // public
	if ( i < 0 || (unsigned)i < getObjects().size() )
		return NULL;
	else
		return getObjects().at( i );
}

Object* Room::getObject( const std::string& name ) { // public
	for ( std::vector< Object* >::iterator it = getObjects().begin(); it != getObjects().end(); ++it )
		if ( strstr( (*it)->getName(), name ) )
			return *it;
	return NULL;
}

bool Room::drop( Object* object ) { // public
	for ( std::vector< Object* >::iterator it = getObjects().begin(); it != getObjects().end(); it++ )
		if ( (*it) == object ) {
			getObjects().erase( it );
			return true;
		}
	return false;
}

bool Room::dropObject( std::string& name ) { // public
	for ( std::vector< Object* >::iterator it = getObjects().begin(); it != getObjects().end(); it++ )
		if ( (*it)->getName() == name ) {
			getObjects().erase( it );
			return true;
		}
	return false;
}

// General methods...
void Room::send( const std::string& message ) {
	for ( std::vector< Character* >::iterator it = getCharacters().begin(); it != getCharacters().end(); it++ )
		if ( (*it)->getStatus() >= CONNECTED ) // I check for this just in case.
			(*it)->Send( message );
	return;
}

bool Room::noExits( void ) { // public
	// Returns true if there are no set exits in the Room.
	for ( int i=0; i < 6; i++ )
		if ( getExit( i )->getThere() )
			return false;

	return true;
}

// Static methods...
std::string Room::sector2string( const unsigned& sector ) { // static
	switch( sector ) {
		case 0: return "indoor";
		case 1: return "city";
		case 2: return "plains";
		case 3: return "forest";
		case 4: return "swamp";
		case 5: return "mountain";
		case 6: return "road";
		case 7: return "underwater";
		case 8: return "graveyard";
		case 9: return "church";
		case 10: return "arena";
		default:
			std::string message;
			message << "Default hit in Room::sector2string() in " << __FILE__ << " line " << __LINE__;
			log( message, SERVER );
			return "{Rerror{x";
	}
}

// Associated operators...
std::ostream& operator << ( std::ostream& write, Room& room ) { // associated
	write << "\n**ROOM\n";
	write << room.getVnum() << ' ' << room.getSector() << ' ' << room.getFlags() << '\n';
	write << room.getName() << "\n";
	write << room.getDesc() << "~\n";
	for ( int x=0; x < 6; x++ )
		write << room.getExit( x );
	write << '\n';

	return write;
}

std::ostream& operator << ( std::ostream& write, Room* room ) { // associated
	return ( write << *room );
}

std::istream& operator >> ( std::istream& read, Room& room ) { // associated
	unsigned vnum = 0, sector = 0, flags = 0;
	char ctemp[MAX_BUFFER];

	read >> vnum >> sector >> flags;
	room.setVnum( vnum );
	room.setSector( sector );	// Do it this way so the room description color (_descolor) is set automatically for us.
	room.setFlags( flags );
	read.get();				// Kills an extra newline before we start doing getline()'s.
	read.getline( ctemp, 500 );
	room.setName( std::string( ctemp ) );
	read.getline( ctemp, MAX_BUFFER, '~' );
	room.setDesc( std::string( ctemp) );
	for ( int x=0; x < 6; x++ )
		read >> room.getExit( x );

	return read;
}

std::istream& operator >> ( std::istream& read, Room* room ) { // associated
	return ( read >> *room );
}
